#include "LogiLcd.h"

#include <QtCore/QDebug>
#include <QtCore/QFile>
#include <QtGui/QImage>
#include <QtGui/QPainter>

LogiLcd::LogiLcd(QString title)
	: QObject(0), title(title)
{
	timer=NULL;
	lastPressed=0;
	LogiLcdInit=NULL;
	LogiLcdIsConnected=NULL;
	LogiLcdIsButtonPressed=NULL;
	LogiLcdUpdate=NULL;
	LogiLcdShutdown=NULL;
	LogiLcdMonoSetBackground=NULL;
	LogiLcdMonoSetText=NULL;
	LogiLcdColorSetBackground=NULL;
	LogiLcdColorSetTitle=NULL;
	LogiLcdColorSetText=NULL;
	isInit=false;
	repeate=false;

	HINSTANCE logiDllHandle = LoadLibrary(L"LogitechLcd.dll");

	if(logiDllHandle == NULL)
	{
#if defined(_M_X64)
		logiDllHandle = LoadLibrary(L"../LogiLcd/LogitechLcd.x64.dll");
#else
		logiDllHandle = LoadLibrary(L"../LogiLcd/LogitechLcd.x32.dll");
#endif
	}
	if (logiDllHandle != NULL)
	{
		LogiLcdInit = (LPFNDLLINIT)GetProcAddress(logiDllHandle, "LogiLcdInit");
		LogiLcdIsConnected = (LPFNDLLISCONNECTED)GetProcAddress(logiDllHandle, "LogiLcdIsConnected");
		LogiLcdIsButtonPressed = (LPFNDLLISBUTTONPRESSED)GetProcAddress(logiDllHandle, "LogiLcdIsButtonPressed");
		LogiLcdUpdate = (LPFNDLLUPDATE)GetProcAddress(logiDllHandle, "LogiLcdUpdate");
		LogiLcdShutdown = (LPFNDLLSHUTDOWN)GetProcAddress(logiDllHandle, "LogiLcdShutdown");
		LogiLcdMonoSetBackground = (LPFNDLLMONOSETBACKGROUND)GetProcAddress(logiDllHandle, "LogiLcdMonoSetBackground");
		LogiLcdMonoSetText = (LPFNDLLMONOSETTEXT)GetProcAddress(logiDllHandle, "LogiLcdMonoSetText");
		LogiLcdColorSetBackground = (LPFNDLLCCOLORSETBACKGROUND)GetProcAddress(logiDllHandle, "LogiLcdColorSetBackground");
		LogiLcdColorSetTitle = (LPFNDLLCOLORSETTITLE)GetProcAddress(logiDllHandle, "LogiLcdColorSetTitle");
		LogiLcdColorSetText = (LPFNDLLCOLORSETTEXT)GetProcAddress(logiDllHandle, "LogiLcdColorSetText");

		init();

		timer = new QTimer();
		timer->setInterval(100);
		connect(timer, SIGNAL(timeout()), this, SLOT(timeout()));
		timer->start();

		//SetRandomBackground();
		//SetMonoBackgroundFromFile("D:\\Documents\\Visual Studio 2012\\Projects\\LcdLogitechApplets\\LogiLcd\\Resources\\tumblr_mtn3yyhj2m1s50cbxo1_1280.jpg",Qt::KeepAspectRatio,Qt::AlignCenter);
		//SetMonoBackgroundFromFile("D:\\Documents\\Visual Studio 2012\\Projects\\LcdLogitechApplets\\LogiLcd\\Resources\\LogiLogoMono.bmp",Qt::KeepAspectRatio,Qt::AlignCenter);
		//SetMonoAutoText("test test test test test test test7 test8 test test test test test test test test test test test test test test test test test test test test ");
	}
}

LogiLcd::~LogiLcd()
{
	if(isInit)
		LogiLcdShutdown();
	if(timer!=NULL)
		timer->stop();
}

void LogiLcd::init()
{
	if(isInit)
	{
		LogiLcdShutdown();
	}

	bool ret = LogiLcdInit((wchar_t *)title.utf16(),LOGI_LCD_TYPE_MONO);
	LogiLcdUpdate();

	if(ret && !LogiLcdIsConnected(LOGI_LCD_TYPE_MONO))
	{
		isInit = false;
		LogiLcdShutdown();
	}
	else
	{
		isInit = ret;
	}
}

void LogiLcd::setInterval(int msec)
{
	if(timer!=NULL)
		timer->setInterval(msec);
}

void LogiLcd::timeout()
{
	if(!isInit){
		init();
	}
	LogiLcdUpdate();

	int pressed = 0;
	if(LogiLcdIsConnected(LOGI_LCD_TYPE_MONO))
	{
		if(LogiLcdIsButtonPressed(LOGI_LCD_MONO_BUTTON_0))
			pressed = pressed | LOGI_LCD_MONO_BUTTON_0;
		if(LogiLcdIsButtonPressed(LOGI_LCD_MONO_BUTTON_1))
			pressed = pressed | LOGI_LCD_MONO_BUTTON_1;
		if(LogiLcdIsButtonPressed(LOGI_LCD_MONO_BUTTON_2))
			pressed = pressed | LOGI_LCD_MONO_BUTTON_2;
		if(LogiLcdIsButtonPressed(LOGI_LCD_MONO_BUTTON_3))
			pressed = pressed | LOGI_LCD_MONO_BUTTON_3;
	}

	if(repeate || lastPressed!=pressed)
		emit buttonPressed(pressed);

	lastPressed = pressed;
}

void LogiLcd::SetMonoText(QString line1, QString line2, QString line3, QString line4)
{
	if(isInit && LogiLcdIsConnected(LOGI_LCD_TYPE_MONO))
	{
		LogiLcdMonoSetText(0, (wchar_t *)line1.utf16());
		LogiLcdMonoSetText(1, (wchar_t *)line2.utf16());
		LogiLcdMonoSetText(2, (wchar_t *)line3.utf16());
		LogiLcdMonoSetText(3, (wchar_t *)line4.utf16());
	}
}

void LogiLcd::SetMonoText(int line, QString text)
{
	if(isInit && LogiLcdIsConnected(LOGI_LCD_TYPE_MONO))
	{
		LogiLcdMonoSetText(line, (wchar_t *)text.utf16());
	}
}

void LogiLcd::SetColorTitle(QString text,int r,int g,int b)
{
	if(isInit && LogiLcdIsConnected(LOGI_LCD_TYPE_COLOR))
	{
		LogiLcdColorSetTitle((wchar_t *)text.utf16(), r, g, b);
	}
}
void LogiLcd::SetColorText(int line, QString text,int r,int g,int b)
{
	if(isInit && LogiLcdIsConnected(LOGI_LCD_TYPE_COLOR))
	{
		LogiLcdColorSetText(line, (wchar_t *)text.utf16(), r, g, b);
	}
}

/**
* Need QApplication(argc,argv,false)
*/
void LogiLcd::SetMonoAutoText(QString text, QString font,  int size, bool white, int flags)
{
	SetMonoAutoText(text, QFont(font, size), white?Qt::white:Qt::black, flags);
}
void LogiLcd::SetMonoAutoText(QString text, QFont font, Qt::GlobalColor color, int flags)
{
	if(isInit && LogiLcdIsConnected(LOGI_LCD_TYPE_MONO))
	{
		QImage img(LOGI_LCD_MONO_WIDTH,LOGI_LCD_MONO_HEIGHT,QImage::Format_RGB32);
		if(color==Qt::white)
			img.fill(0);
		else img.fill(128);

		QPainter painter(&img);
		painter.setPen(color);
		painter.setFont(font);
		painter.drawText(0, 0, LOGI_LCD_MONO_WIDTH, LOGI_LCD_MONO_HEIGHT, flags, text);
		painter.end();

		SetMonoBackgroundFromImage(img);
	}
}

bool LogiLcd::SetRandomBackground()
{
	bool res = false;

	if(isInit && LogiLcdIsConnected(LOGI_LCD_TYPE_MONO))
	{
		BYTE pixels[LOGI_LCD_MONO_WIDTH * LOGI_LCD_MONO_HEIGHT];
		for (int i = 0; i < (LOGI_LCD_MONO_WIDTH * LOGI_LCD_MONO_HEIGHT); i++)
		{
			pixels[i] = (BYTE)rand();
		}
		res = LogiLcdMonoSetBackground(pixels);
		LogiLcdUpdate();

	}

	if(isInit && LogiLcdIsConnected(LOGI_LCD_TYPE_COLOR))
	{
		BYTE colorBitmap[LOGI_LCD_COLOR_WIDTH * LOGI_LCD_COLOR_HEIGHT * 4];
		for (int i = 0; i < (LOGI_LCD_COLOR_WIDTH * LOGI_LCD_COLOR_HEIGHT * 4); i++)
		{
			colorBitmap[i] = (BYTE)rand();
		}
		res = LogiLcdColorSetBackground(colorBitmap);
		LogiLcdUpdate();
	}
	return res;
}

bool LogiLcd::SetMonoBackgroundFromFile(QString fileName, Qt::AspectRatioMode aspectMode, Qt::AlignmentFlag alignment)
{
	if(!isInit || !LogiLcdIsConnected(LOGI_LCD_TYPE_MONO))
	{
		return false;
	}
	QFile file(fileName);
	if (!file.open(QIODevice::ReadOnly)) {      
		qDebug()<<"Error: "<<file.error()<<":"<<file.errorString();
		return false;
	}

	QByteArray blob = file.readAll(); 
	file.close();

	return SetMonoBackgroundFromFile(blob);
}

bool LogiLcd::SetMonoBackgroundFromByteArray(QByteArray blob, Qt::AspectRatioMode aspectMode, Qt::AlignmentFlag alignment)
{
	return SetMonoBackgroundFromImage(QImage::fromData(blob), aspectMode, alignment);
}
bool LogiLcd::SetMonoBackgroundFromImage(QImage img, Qt::AspectRatioMode aspectMode, Qt::AlignmentFlag alignment)
{
	if(!isInit || !LogiLcdIsConnected(LOGI_LCD_TYPE_MONO))
	{
		return false;
	}

	if (img.isNull()) {      
		qDebug()<<"Error: img.isNull()";
		return false;
	}
	if(img.width()!=LOGI_LCD_MONO_WIDTH || img.height()!=LOGI_LCD_MONO_HEIGHT)
	{
		img = img.scaled(LOGI_LCD_MONO_WIDTH, LOGI_LCD_MONO_HEIGHT, aspectMode);
	}

	if(img.format()!=QImage::Format_Indexed8)
		img = img.convertToFormat(QImage::Format_Indexed8,Qt::MonoOnly);

	int left = 0;
	//TODO combiner avec AlignTop & AlignBottom
	switch(alignment)
	{
	case Qt::AlignLeft:
		left = 0;
		break;
	case Qt::AlignRight:
		left = LOGI_LCD_MONO_WIDTH - img.width();
		break;
	case Qt::AlignCenter:
		left = (LOGI_LCD_MONO_WIDTH - img.width()) / 2;
		break;
	}

	BYTE byteBitmapMono8bpp[LOGI_LCD_MONO_WIDTH * LOGI_LCD_MONO_HEIGHT];
	for (int y = 0;y<img.height();++y)
	{

		for (int x=0;x<left;++x)
		{
			byteBitmapMono8bpp[y*LOGI_LCD_MONO_WIDTH + x] = 0;
		}
		for (int x=left;x<left+img.width();++x)
		{
			byteBitmapMono8bpp[y*LOGI_LCD_MONO_WIDTH + x] = img.pixel(x-left,y);
		}
		for (int x=left+img.width();x<LOGI_LCD_MONO_WIDTH;++x)
		{
			byteBitmapMono8bpp[y*LOGI_LCD_MONO_WIDTH + x] = 0;
		}
	}
	for (int y = img.height();y<LOGI_LCD_MONO_HEIGHT;++y)
	{
		for (int x=0;x<LOGI_LCD_MONO_WIDTH;++x)
		{
			byteBitmapMono8bpp[y*LOGI_LCD_MONO_WIDTH + x] = 0;
		}
	}
	bool ret = LogiLcdMonoSetBackground(byteBitmapMono8bpp);

	LogiLcdUpdate();
	return ret;
}

bool LogiLcd::SetColorBackgroundFromFile(QString fileName)
{
	if(!isInit || !LogiLcdIsConnected(LOGI_LCD_TYPE_COLOR))
	{
		return false;
	}
	QFile file(fileName);
	if (!file.open(QIODevice::ReadOnly)) {      
		qDebug()<<"Error: "<<file.error()<<":"<<file.errorString();
		return false;
	}

	QByteArray blob = file.readAll(); 
	file.close();

	QImage img = QImage::fromData(blob);
	/*if(img.width()!=LOGI_LCD_COLOR_WIDTH || img.height()!=LOGI_LCD_COLOR_HEIGHT)
	{
	qDebug()<<"Error: "<<img.size()<<" <> "<<LOGI_LCD_COLOR_WIDTH<<"x"<<LOGI_LCD_COLOR_HEIGHT;
	return false;
	}*/

	bool ret = LogiLcdColorSetBackground(img.bits());

	LogiLcdUpdate();
	return ret;
}

bool LogiLcd::ResetScreen()
{
	bool res = false;

	if(isInit && LogiLcdIsConnected(LOGI_LCD_TYPE_MONO))
	{
		BYTE pixels[LOGI_LCD_MONO_WIDTH * LOGI_LCD_MONO_HEIGHT];
		res = LogiLcdMonoSetBackground(pixels);
		SetMonoText(0, "");
		SetMonoText(1, "");
		SetMonoText(2, "");
		SetMonoText(3, "");
	}

	if(isInit && LogiLcdIsConnected(LOGI_LCD_TYPE_COLOR))
	{
		BYTE colorBitmap[LOGI_LCD_COLOR_WIDTH * LOGI_LCD_COLOR_HEIGHT * 4];
		res = LogiLcdColorSetBackground(colorBitmap);
		SetColorTitle("", 0, 0, 0);
		SetColorText(0, "", 0, 0, 0);
		SetColorText(1, "", 0, 0, 0);
		SetColorText(2, "", 0, 0, 0);
		SetColorText(3, "", 0, 0, 0);
		SetColorText(4, "", 0, 0, 0);
		SetColorText(5, "", 0, 0, 0);
		SetColorText(6, "", 0, 0, 0);
		SetColorText(7, "", 0, 0, 0);
	}

	return res;
}